﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;

using EdgeStatz.ESSystems.Objects;

namespace EdgeStatz.ModelEngine.FormTools
{
    class FormToolsXml
    {
        private List<FormDefinition> formDefinitions = new List<FormDefinition> { };

        private string xmlFilePath;
        private string modelname;
        private string modelpath;
        private string assemblyname;

        public string ModelPath
        {
            get 
            {
                if (!modelpath.EndsWith("\\"))
                    modelpath += "\\";
                return modelpath; 
            }
        }

        public string ModelName
        {
            get { return modelname; }
        }        

        public FormDefinition[] FormDefinitions
        {
            get { return formDefinitions.ToArray(); }
            set
            {
                formDefinitions = new List<FormDefinition> { };
                formDefinitions.AddRange(value);
            }
        }
        public string XmlFilePath
        {
            set { xmlFilePath = value; }
            get { return xmlFilePath; }
        }
        public string AssemblyName
        {
            get { return assemblyname; }
            set { assemblyname = value; }
        }

        public FormToolsXml(string path)
        {
            using (XmlTextReader xmlReader = new XmlTextReader(path))
                xmlFilePath = xmlReader.BaseURI;
            Init();
        }
        public void AddFormDefinition(FormDefinition value)
        {
            if (FormDefinitionExists(value.Name))
                ReplaceFormDefinitionByFolderName(value, value.Name);
            else
                formDefinitions.Add(value);
        }
        public void ReplaceFormDefinitionByFolderName(FormDefinition value, string name)
        {
            int index = formDefinitions.FindIndex(
                delegate(FormDefinition fdef)
                {
                    return fdef.Folder.ToUpper().Equals(name.ToUpper());
                });
            formDefinitions.Insert(index, value);
            formDefinitions.RemoveAt(index + 1);
        }
        public bool FormDefinitionExists(string formname)
        {
            int index = formDefinitions.FindIndex(
                delegate(FormDefinition fdef)
                {
                    return fdef.Folder.ToUpper().Equals(formname.ToUpper());
                });
            if (index == -1)
                return false;
            return true;
        }

        #region Read
        private void Init() 
        { 
            XmlDocument myXmlDocument = new XmlDocument();
            myXmlDocument.Load(XmlFilePath);

            XmlNode rootNode;
            rootNode = myXmlDocument.DocumentElement;
            modelname = rootNode.Attributes["Name"].Value;
            modelpath = rootNode.Attributes["Path"].Value;

            formDefinitions.Clear();

            foreach (XmlNode node1 in rootNode.ChildNodes)
            {
                if (node1.Name.ToUpper() == "FORMS")
                {
                    assemblyname = node1.Attributes["Assembly"] == null ? null : node1.Attributes["Assembly"].Value;
                    foreach (XmlNode node2 in node1.ChildNodes)
                    {
                        if (node2.Name.ToUpper() == "FORM")
                        {
                            if (node2.Attributes["Type"] == null)
                                throw new Exception("Type tag is required for Form controls.");

                            switch (node2.Attributes["Type"].Value.ToUpper())
                            {
                                case "FILE":
                                    formDefinitions.Add(DoFileRead(node2));
                                    break;
                                case "SOURCE":
                                    formDefinitions.Add(DoSourceRead(node2));
                                    break;
                                case "COMPILED":
                                    formDefinitions.Add(DoCompiledRead(node2));
                                    break;
                            }
                        }
                    }
                }
            }
        }

        private FormDefinition DoFileRead(XmlNode node1)
        {
            List<string> cps = new List<string> { };
            List<string> rex = new List<string> { };
            foreach (XmlNode node2 in node1.ChildNodes)
            {
                if (node2.Name.ToUpper() == "COMPILEPARAMETER")
                {
                    if (node2.InnerText == null || node2.InnerText == "")
                        throw new Exception("Compile Parameter cannot be null.");
                    cps.Add(node2.InnerText);
                }
                else if (node2.Name.ToUpper() == "RESOURCE")
                {
                    if (node2.InnerText == null || node2.InnerText == "")
                        throw new Exception("Resource Parameter cannot be null.");
                    rex.Add(node2.InnerText);
                }
            }
            return new FormDefinition(
                node1.Attributes["Name"].Value, 
                node1.Attributes["Folder"].Value, 
                node1.Attributes["File"].Value, 
                cps.ToArray(), rex.ToArray());
        }
        
        private FormDefinition DoSourceRead(XmlNode node1)
        {
            TextWriter file = null;
            string path = GlobalSystemSettings.SystemFolderPath;
            string name = node1.Attributes["Name"].Value;
            string folder = node1.Attributes["Folder"].Value;

            file = new StreamWriter(path + name + "_Form.cs", false);

            List<string> cps = new List<string> { };
            List<string> rex = new List<string> { };
            foreach (XmlNode node2 in node1.ChildNodes)
            {
                if (node2.Name.ToUpper() == "COMPILEPARAMETER")
                {
                    if (node2.InnerText == null || node2.InnerText == "")
                        throw new Exception("Compile Parameter cannot be null.");
                    cps.Add(node2.InnerText);
                }
                else if (node2.Name.ToUpper() == "RESOURCE")
                {
                    if (node2.InnerText == null || node2.InnerText == "")
                        throw new Exception("Resource Parameter cannot be null.");
                    rex.Add(node2.InnerText);
                }
                else if (node2.Name.ToUpper() == "STRING")
                {
                    file.WriteLine(node2.InnerText == null ? "" : node2.InnerText);
                }
            }
            file.Close();

            return new FormDefinition(
                name, folder, (path + name + "_Form.cs"), cps.ToArray(), rex.ToArray());
        }

        private FormDefinition DoCompiledRead(XmlNode node1)
        {
            return new FormDefinition(
                node1.Attributes["Name"].Value,
                node1.Attributes["Folder"].Value);
        }

        #endregion

        #region Save

        public void SaveFile()
        {
            XmlDocument myXmlDocument = new XmlDocument();
            myXmlDocument.Load(XmlFilePath);

            XmlNode rootNode;
            rootNode = myXmlDocument.DocumentElement;

            foreach (XmlNode node1 in rootNode.ChildNodes)
            {
                if (node1.Name.ToUpper() == "FORMS")
                {
                    XmlNode formsnode = myXmlDocument.CreateNode(XmlNodeType.Element, "Forms", "");
                    if (assemblyname != null)
                    {
                        XmlAttribute attributeassembly = myXmlDocument.CreateAttribute("Assembly");
                        attributeassembly.Value = assemblyname;
                        formsnode.Attributes.Append(attributeassembly);
                    }

                    foreach (FormDefinition fd in FormDefinitions)
                    {
                        XmlNode child = myXmlDocument.CreateNode(XmlNodeType.Element, "Form", "");
                        XmlAttribute attributename = myXmlDocument.CreateAttribute("Name");
                        XmlAttribute attributefolder = myXmlDocument.CreateAttribute("Folder");
                        XmlAttribute attributetype = myXmlDocument.CreateAttribute("Type");
                        XmlAttribute attributefile = myXmlDocument.CreateAttribute("File");

                        attributename.Value = fd.Name;
                        attributefolder.Value = fd.Folder;
                        child.Attributes.Append(attributename);
                        child.Attributes.Append(attributefolder);

                        if (fd.FilePath == null || fd.FilePath == "")
                        {
                            attributetype.Value = "Compiled";
                            child.Attributes.Append(attributetype);
                        }
                        else
                        {
                            attributetype.Value = "File";
                            attributefile.Value = fd.FilePath;
                            child.Attributes.Append(attributetype);
                            child.Attributes.Append(attributefile);

                            foreach (string cparam in fd.CompileParameters)
                            {
                                XmlNode cpnode = myXmlDocument.CreateNode(XmlNodeType.Element, "CompileParameter", "");
                                cpnode.InnerText = cparam;

                                child.AppendChild(cpnode);
                            }
                        }
                        formsnode.AppendChild(child);
                    }

                    rootNode.ReplaceChild(formsnode, node1);
                    myXmlDocument.Save(XmlFilePath.Remove(0, 8));
                    Init();
                    return;
                }
            }
            throw new Exception("File must contain a <forms> node.");
        }

        #endregion

        public void CancelChanges()
        {
            Init();
        }
    }
}
